﻿using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Sgr.Application;
using Sgr.Application.Commands;
using Sgr.BackGroundTasks;
using Sgr.Email.BackGroundTasks;
using Sgr.Identity;
using Sgr.Identity.Services;
using Sgr.Security.VerifyCode;
using Sgr.Sms.BackGroundTasks;
using Sgr.Utilities;
using System.Text.RegularExpressions;

namespace Sgr.Indentity.Application.Commands
{
    public class SendVerificationCodeCommandHandler : IRequestHandler<SendVerificationCodeCommand, CommandResult<bool>>
    {
        private readonly IVerifyCodeService _verifyCodeService;
        private readonly IAccountAuthService _accountAuthService;
        private readonly ILogger<SendVerificationCodeCommandHandler> _logger;
        private readonly IdentityOptions _options;
        private readonly ISignatureChecker _signatureChecker;
        private readonly IBackGroundTaskManager _backGroundTaskManager;
        private readonly IConfiguration _configuration;

        public SendVerificationCodeCommandHandler(
            IVerifyCodeService verifyCodeService,
            IAccountAuthService accountAuthService,
            ISignatureChecker signatureChecker,
            IBackGroundTaskManager backGroundTaskManager,
            IOptions<IdentityOptions> options,
            IConfiguration configuration,
            ILogger<SendVerificationCodeCommandHandler> logger)
        {
            _verifyCodeService = verifyCodeService ?? throw new ArgumentNullException(nameof(verifyCodeService));
            _accountAuthService = accountAuthService ?? throw new ArgumentNullException(nameof(accountAuthService));
            _signatureChecker = signatureChecker ?? throw new ArgumentNullException(nameof(signatureChecker));
            _backGroundTaskManager = backGroundTaskManager ?? throw new ArgumentNullException(nameof(backGroundTaskManager));
            _options = options.Value ?? throw new ArgumentNullException(nameof(options));
            _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        public async Task<CommandResult<bool>> Handle(SendVerificationCodeCommand request, CancellationToken cancellationToken)
        {
            if (!ValidateRequest(request))
                return CommandResult.Invalid<bool>("请求参数无效");

            try
            {
                if (request.ReceiverMustUnregistered)
                {
                    //接收地址是否为未注册状态
                    if (await _accountAuthService.IsAccountRegistered(request.ReceiverType, request.Receiver, cancellationToken))
                    {
                        return CommandResult.Invalid<bool>($"账号 {request.Receiver} 已注册");
                    }
                }

                // 发送验证码
                int expireMinutes = 5;
                var code = await _verifyCodeService.CreateAsync(
                    request.ReceiverType,
                    request.Receiver,
                    request.Purpose,
                    expireMinutes,
                    cancellationToken);

                // 后台任务发送验证码
                if (request.ReceiverType == ReceiverType.Email)
                {
                    await SendVerificationCodeByEmail(request, code, expireMinutes, cancellationToken);
                }
                else if (request.ReceiverType == ReceiverType.Phone)
                {
                    await SendVerificationCodeByPhone(request, code, expireMinutes, cancellationToken);
                }

                return CommandResult.Success(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发送验证码异常. 接收方: {Receiver}", request.Receiver);
                return CommandResult.Error<bool>("验证码发送异常", ex);
            }
        }

        private async Task SendVerificationCodeByEmail(SendVerificationCodeCommand request, string code, int expireMinutes, CancellationToken cancellationToken)
        {
            string appName = _configuration.GetValue<string>("Sgr:AppName") ?? "SGR";

            var data = new EmailSenderData();

            data.To.Add(request.Receiver);
            data.Subject = appName + " 验证码";
            data.Body = EmailTemplates.GetVerificationCodeTemplate(appName, code, expireMinutes);
            data.IsBodyHtml = true;

            await _backGroundTaskManager.EnqueueAsync<EmailSenderBackGroundTask, EmailSenderData>(data, cancellationToken);
        }

        private async Task SendVerificationCodeByPhone(SendVerificationCodeCommand request, string code, int expireMinutes, CancellationToken cancellationToken)
        {
            string appName = _configuration.GetValue<string>("Sgr:AppName") ?? "SGR";

            // 构建短信内容
            string message = $"【{appName}】您的验证码是：{code}，{expireMinutes}分钟内有效，如非本人操作，请忽略本短信。";

            var data = new SmsSenderData
            {
                PhoneNumber = request.Receiver,
                Message = message
            };

            await _backGroundTaskManager.EnqueueAsync<SmsSenderBackGroundTask, SmsSenderData>(
                data,
                BackGroundTaskPriority.High,  // 验证码短信优先级高
                cancellationToken: cancellationToken);
        }

        private bool ValidateRequest(SendVerificationCodeCommand request)
        {
            // 签名验证
            if (_options.UseSignature)
            {
                if (string.IsNullOrWhiteSpace(request.Signature) ||
                    string.IsNullOrWhiteSpace(request.Timestamp) ||
                    string.IsNullOrWhiteSpace(request.Nonce))
                {
                    return false;
                }

                string secretKey = request.Receiver; // 使用接收方地址作为密钥
                if (!_signatureChecker.VerifySignature(
                    request.Signature,
                    request.Timestamp,
                    request.Nonce,
                    request.ReceiverType + "-" + request.Receiver,
                    secretKey))
                {
                    _logger.LogWarning("验证码请求签名验证失败. 接收方: {Receiver}", request.Receiver);
                    return false;
                }
            }

            return true;
        }
    }
}